
function debounce(fn, time = 50){
	let timer = null;
	return function(...arg) {
		clearTimeout(timer);
		timer = setTimeout(fn.bind(null, ...arg), time)
	}
}
function throttle(fn) {
	let isDoindg = false;
	return async function(...arg){
		if(isDoindg) return;
		isDoindg = true;
		const result = await fn.apply(null, arg)
		isDoindg =  false;
		return result
	}
}
function createTimeOut(fn, time = 50){
	return function(...arg) {
	  return	new Promise((resolve, reject)=>{
				setTimeout(_=>{
					fn.apply(null, arg)
					resolve()
				}, time)
			})
	}
}
const painType = {
	type: "line",
	colort: "#000",
	width: 1,
	list: [
		{
			x: 0,
			y: 0,
		},
	],
};
class Paint {
	constructor(opts) {
		const defaultOpts = {
			width: window.innerWidth,
			height: window.innerHeight,
		};
		opts = {
			...defaultOpts,
			...opts,
		};
		const canvas = this.canvas = opts.canvas || document.createElement("canvas");
		const canvasRect = canvas.getBoundingClientRect();
		this.isMousedown = false;
		canvas.width = this.width = opts.width;
		canvas.height = this.height = opts.height;
		this.ctx = canvas.getContext("2d");
		this.lineStyle = "#000";
		this.lineWidth = 5;
		this.endIndex = -1;
		this.paintList = []; // 画图的列表
		this.currentPaint = null;
		this.imageData = null;
		this.pos = {
			x: canvasRect.x,
			y: canvasRect.y
		}
		this.bindEvent();
	}
	// 清空画布
	clearRect() {
		this.ctx.clearRect(0, 0, this.width, this.height);
	}
	// 撤销
	undo() {
		if(this.endIndex <0) return;
		this.endIndex--;
		this.draw();
	}
	reduction() {
		if(this.endIndex >= this.paintList.length -1) return;
		this.endIndex++;
		this.draw();
	}
	// 整体绘图
	draw() {
		this.clearRect();
		if(this.imageData) {
			this.ctx.putImageData(this.imageData, 0, 0);
			this.drawPaintItem(this.currentPaint);
			return
		}
		for(let i =0;i<=this.endIndex;i++) {
			this.drawPaintItem(this.paintList[i]);			
		}
	}
	drawPaintItem(item) {
		const drawFnMap = {
			line: "drawLine",
		};
		const ctx = this.ctx;
		ctx.beginPath();
		this[drawFnMap[item.type]](item);
		ctx.closePath();
	}
	// 画线
	drawLine(opts) {
		const { color, width, list:lineList } = opts;
		const ctx = this.ctx;
		ctx.fillStyle = color;
		ctx.lineWidth = width;
		if(lineList.length > 3) {
			ctx.beginPath();
			let index = 0;
			let startPoint = lineList[index ++];
			ctx.moveTo(startPoint.x, startPoint.y);
			while(index < lineList.length - 1) {
				const controlPoint = lineList[index ++];
				const lastPoint = lineList[index];
				const endPoint = {
					x: (controlPoint.x + lastPoint.x) / 2,
					y: (controlPoint.y + lastPoint.y) / 2
				}
				ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
			}
			const point = lineList[index];
			ctx.lineTo(point.x, point.y);
			ctx.stroke()
		}
	}
	// 绑定初始事件
	bindEvent() {
		this.canvas.addEventListener("mousedown", this.mouseDownHandle);
		document.addEventListener('keydown', e=>{
			if(e.ctrlKey) {
				if(e.key === 'z'){
					this.undo()
				}
				if(e.key === 'y'){
					this.reduction()
				}
			}
		})
	}
	getPoint(e) {
		return {
			x: parseInt(e.clientX - this.pos.x, 10),
			y: parseInt(e.clientY - this.pos.y, 10),
		}
	}
	
	// 绑定鼠标移动事件(绑定在document上)
	addMoveListener() {
		document.addEventListener("mousemove", this.moveHandle);
		document.addEventListener("mouseup", this.moveEndHandle);
	}
	// 移除鼠标移动事件（移除document上的事件）
	removeMoveListener() {
		document.removeEventListener("mousemove", this.moveHandle);
		document.removeEventListener("mouseup", this.moveEndHandle);
	}

	mouseDownHandle =(e)=> {
		this.addMoveListener();
		this.isMousedown = true;
		this.imageData = this.ctx.getImageData(0, 0, this.width, this.height);
		const currentPaint = this.currentPaint = {
			type: 'line',
			color: this.lineStyle,
			width: this.lineWidth,
			list: [this.getPoint(e)]
		};
		const paintList = this.paintList.slice(0, ++this.endIndex);
		paintList.push(currentPaint);
		this.paintList = paintList;
		this.draw();
	}
	moveHandle = throttle(createTimeOut((e)=> {
		if (!this.isMousedown || e.target != this.canvas) return;
		const currentPaint = this.currentPaint;
		const {list} = currentPaint;
		list.push(this.getPoint(e));
		this.draw();
	}, 10))
	moveEndHandle =(e)=> {
		this.removeMoveListener();
		const currentPaint = this.currentPaint;
		const {list} = currentPaint;
		list.push(this.getPoint(e));
		this.draw()
		this.imageData = null;
		this.isMousedown = false;
		this.currentPaint = null;
	}
	setWidth(width){
		if(isNaN(width)) return;
		this.lineWidth = width;
	}
	getWidth(){
		return this.lineWidth
	}
}

const paint = new Paint({
	canvas: document.getElementById("drawing-canvas"),
	width: 800,
	height: 800
});

const widthItems = document.querySelectorAll('.line-item');
Array.from(widthItems).forEach(widthItem=>{
	widthItem.addEventListener('click', function(e){
		const width = e.currentTarget.getAttribute('data-width');
		console.log(width);
		paint.setWidth(+width);
		addWidthActive()
	})
})

function addWidthActive(){
	var width = +paint.getWidth();
	Array.from(widthItems).forEach(widthItem=>{
		const itemWidth = +widthItem.getAttribute('data-width');
		if(width === itemWidth) widthItem.classList.add('active')
		else widthItem.classList.remove('active')
	})
}
addWidthActive()